Business Understand

Telco é uma empresa de telecomunicações americana, reconhecida por serviços residenciais como televisão por assinatura, acesso à internet e telefonia fixa.
Em uma reunião da empresa entre os gerentes e CEO, foi averiguado que taxa de churn dos clientes está em 26% o que é muito alto , quando o aceitavel seria algo em torno de 5%.
Sendo assim o CEO pediu ao gerente da área de Data Science para criar uma solução que diminua a taxa de churn.

Challenges

  • Entender o porque do desligamento dos clientes.
  • Como se antecipar a clientes que tem intensão de sair da empresa e assim oferecer incentivos para que esse cliente continue conosco e assim diminuir o custo de aquisição de novos clientes.

Analytic approach

Time de Data sciences se reuniu e propôs duas soluções para problema:

Data requirements

Loading packages

library(tidyverse)
library(DT)
library(plotly)

theme_set(theme_minimal())

Functions

predmodel_datatable <- function(dataset){
  dataset %>% 
      datatable(escape = FALSE,
                rownames = FALSE,
                options = list(dom = 'ltipr',
                               ordering = FALSE,
                               scrollY = "200px",
                               scrollX = TRUE,
                               scrollCollapse = TRUE,
                               paging = FALSE,
                               searchHighlight = TRUE))
}

Data Collection

Loading data

df_raw <- data.table::fread("~/repos/Increasing-the-Retention-Rate/Data/WA_Fn-UseC_-Telco-Customer-Churn.csv")

head(df_raw) %>% 
  predmodel_datatable()

Data understand

Data Description Table

descricao <-  c("indentificador unico do cliente.  ","Se cliente é homem ou mulher.  ","Se cliente é idoso ou não.  ",
             "Se cliente é casado ou não.  ","Se cliente possui dependentes ou não.  ",
             "Número de meses que o cliente permaneceu na empresa.  ","Se o cliente tem serviço de telefônico ou não.  ",
             "Se o cliente tem várias linhas ou não.   ", "Se cliente tem serviço de internet.  ",
             "Se o cliente tem serviço de anti-virus ou não.  ", 
             "Indica se o cliente assina um serviço de backup online adicional fornecido pela empresa.  ",
             "Indica se o cliente assina um plano de proteção de dispositivo adicional para seu equipamento de Internet fornecido pela empresa.",  "Indica se o cliente assina um plano de suporte técnico adicional da empresa com tempos de espera reduzidos.  ",
             "Indica se o cliente usa seu serviço de Internet para transmitir programas de televisão de um provedor terceirizado.  ",
             "Indica se o cliente usa seu serviço de Internet para transmitir filmes de um provedor terceirizado.  ",
             "Indica o tipo de contrato atual do cliente: mês a mês, um ano, dois anos.  ",
             "Indica se o cliente escolheu faturamento sem boleto.  ",
             "Indica como o cliente paga sua fatura: saque bancário, cartão de crédito, cheque enviado.  ",
             "Indica a cobrança mensal total atual do cliente por todos os seus serviços da empresa.  ",
             "Indica as cobranças totais do cliente, calculadas até o final do trimestre especificado acima. ",
             "Indica se cliente deixou a empresa ou não.")   

tbl_descricao <- tibble(variavel = colnames(df_raw),
       descricao = descricao)

tbl_descricao %>% 
  predmodel_datatable()

Number of rows and columns

print(paste("Number of Rows: " ,nrow(df_raw)))
[1] "Number of Rows:  7043"
print(paste("Number of Cols: " ,ncol(df_raw)))
[1] "Number of Cols:  21"

Data types

glimpse(df_raw)
Rows: 7,043
Columns: 21
$ customerID       <chr> "7590-VHVEG", "5575-GNVDE", "3668-QPYBK", "7795-CFOCW…
$ gender           <chr> "Female", "Male", "Male", "Male", "Female", "Female",…
$ SeniorCitizen    <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ Partner          <chr> "Yes", "No", "No", "No", "No", "No", "No", "No", "Yes…
$ Dependents       <chr> "No", "No", "No", "No", "No", "No", "Yes", "No", "No"…
$ tenure           <int> 1, 34, 2, 45, 2, 8, 22, 10, 28, 62, 13, 16, 58, 49, 2…
$ PhoneService     <chr> "No", "Yes", "Yes", "No", "Yes", "Yes", "Yes", "No", …
$ MultipleLines    <chr> "No phone service", "No", "No", "No phone service", "…
$ InternetService  <chr> "DSL", "DSL", "DSL", "DSL", "Fiber optic", "Fiber opt…
$ OnlineSecurity   <chr> "No", "Yes", "Yes", "Yes", "No", "No", "No", "Yes", "…
$ OnlineBackup     <chr> "Yes", "No", "Yes", "No", "No", "No", "Yes", "No", "N…
$ DeviceProtection <chr> "No", "Yes", "No", "Yes", "No", "Yes", "No", "No", "Y…
$ TechSupport      <chr> "No", "No", "No", "Yes", "No", "No", "No", "No", "Yes…
$ StreamingTV      <chr> "No", "No", "No", "No", "No", "Yes", "Yes", "No", "Ye…
$ StreamingMovies  <chr> "No", "No", "No", "No", "No", "Yes", "No", "No", "Yes…
$ Contract         <chr> "Month-to-month", "One year", "Month-to-month", "One …
$ PaperlessBilling <chr> "Yes", "No", "Yes", "No", "Yes", "Yes", "Yes", "No", …
$ PaymentMethod    <chr> "Electronic check", "Mailed check", "Mailed check", "…
$ MonthlyCharges   <dbl> 29.85, 56.95, 53.85, 42.30, 70.70, 99.65, 89.10, 29.7…
$ TotalCharges     <dbl> 29.85, 1889.50, 108.15, 1840.75, 151.65, 820.50, 1949…
$ Churn            <chr> "No", "No", "Yes", "No", "Yes", "Yes", "No", "No", "Y…

Checking Missing values

naniar::vis_miss(df_raw)

colSums(is.na(df_raw))
      customerID           gender    SeniorCitizen          Partner 
               0                0                0                0 
      Dependents           tenure     PhoneService    MultipleLines 
               0                0                0                0 
 InternetService   OnlineSecurity     OnlineBackup DeviceProtection 
               0                0                0                0 
     TechSupport      StreamingTV  StreamingMovies         Contract 
               0                0                0                0 
PaperlessBilling    PaymentMethod   MonthlyCharges     TotalCharges 
               0                0                0               11 
           Churn 
               0 

Apenas a variavel TotalCharges possui 11 valores ausentes representando apenas 0.16% da base de dados.

Change type and Fillout:

  • Todas as variaveis que estiverem com tipo character serão convertidas em factor.
  • Excluir os 11 valores ausentes da variavel TotalCharges.
  • Definir na variavel churn Yes como a classe positiva.
  • Nome das variaveis serão aplicadas o metodo snake case.
df1 <- df_raw %>% 
  mutate_if(is.character, as.factor) %>% 
  drop_na(TotalCharges) %>% 
  mutate(Churn = forcats::fct_relevel(Churn, "Yes","No")) %>% 
  janitor::clean_names()

Summary Statistical

summary(df1)
     customer_id      gender     senior_citizen   partner    dependents
 0002-ORFBO:   1   Female:3483   Min.   :0.0000   No :3639   No :4933  
 0003-MKNFE:   1   Male  :3549   1st Qu.:0.0000   Yes:3393   Yes:2099  
 0004-TLHLJ:   1                 Median :0.0000                        
 0011-IGKFF:   1                 Mean   :0.1624                        
 0013-EXCHZ:   1                 3rd Qu.:0.0000                        
 0013-MHZWF:   1                 Max.   :1.0000                        
 (Other)   :7026                                                       
     tenure      phone_service          multiple_lines    internet_service
 Min.   : 1.00   No : 680      No              :3385   DSL        :2416   
 1st Qu.: 9.00   Yes:6352      No phone service: 680   Fiber optic:3096   
 Median :29.00                 Yes             :2967   No         :1520   
 Mean   :32.42                                                            
 3rd Qu.:55.00                                                            
 Max.   :72.00                                                            
                                                                          
            online_security             online_backup 
 No                 :3497   No                 :3087  
 No internet service:1520   No internet service:1520  
 Yes                :2015   Yes                :2425  
                                                      
                                                      
                                                      
                                                      
           device_protection              tech_support 
 No                 :3094    No                 :3472  
 No internet service:1520    No internet service:1520  
 Yes                :2418    Yes                :2040  
                                                       
                                                       
                                                       
                                                       
              streaming_tv             streaming_movies           contract   
 No                 :2809   No                 :2781    Month-to-month:3875  
 No internet service:1520   No internet service:1520    One year      :1472  
 Yes                :2703   Yes                :2731    Two year      :1685  
                                                                             
                                                                             
                                                                             
                                                                             
 paperless_billing                   payment_method monthly_charges 
 No :2864          Bank transfer (automatic):1542   Min.   : 18.25  
 Yes:4168          Credit card (automatic)  :1521   1st Qu.: 35.59  
                   Electronic check         :2365   Median : 70.35  
                   Mailed check             :1604   Mean   : 64.80  
                                                    3rd Qu.: 89.86  
                                                    Max.   :118.75  
                                                                    
 total_charges    churn     
 Min.   :  18.8   Yes:1869  
 1st Qu.: 401.4   No :5163  
 Median :1397.5             
 Mean   :2283.3             
 3rd Qu.:3794.7             
 Max.   :8684.8             
                            

As variaveis abaixo possuem informações duplicadas:

  • multiple_lines
  • online_security
  • online_backup
  • device_protection
  • tech_support
  • streaming_tv
  • streaming_movies

Removing Duplicated

df1 <- df1 %>% 
  
  mutate( multiple_lines = recode( multiple_lines,"No phone service" = "No" ) ) %>% # substituindo "No phone service" por "No"
  mutate_at( vars( online_security:streaming_movies ),
            funs( recode( .,"No internet service" = "No" ) ) ) %>% # substituindo "No internet service" por "No"
  mutate( payment_method = recode( payment_method,"Bank transfer (automatic)"= "Bank transfer" ,
                                                  "Credit card (automatic)"  = "Credit card"))# removendo " (automatic) "

Distribution of Numerical Variables

df1 %>%
  keep(is.numeric) %>% 
  gather() %>% 
  ggplot(aes(value)) +
    facet_wrap(~ key, scales = "free") +
    geom_histogram(col= "black", fill="steelblue", bins = 25)+
    scale_y_continuous(labels = function(x) format(x, scientific = FALSE))+
  labs(title = "Distribution of numerical variables")+
  theme(plot.title = element_text(hjust = 0.5, size = 18))

Distribution of Categorical Variables

df1 %>%
  keep(is.factor) %>% 
  select(-customer_id) %>% 
  gather() %>% 
  ggplot(aes(value)) +
    facet_wrap(~ key, scales = "free") +
    geom_bar(col= "black", fill="steelblue", bins = 25)+
    scale_y_continuous(labels = function(x) format(x, scientific = FALSE))+
  labs(title = "Distribution of numerical variables")+
  theme(plot.title = element_text(hjust = 0.5, size = 18))+
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

Feature Engineering

EDA

total_charges: Cobrança total mensal cliente por todos os seus serviços na empresa.

  1. Clientes com valor mensal alto , tendem a ter um churn maior.
p1 <- df1 %>% 
  ggplot(aes(total_charges, fill= churn))+
  geom_histogram(col="black")+
  scale_x_continuous(breaks = seq(0,8000, 500))+
  labs(title = "Distribution of Total Charges by Churn")+
  theme(plot.title = element_text(hjust = 0.5, size = 18))

ggplotly(p1)
  1. Falsa, pois clientes com valores menores que 1500 dolares tem um churn maior.

contract: tipo de contrato atual do cliente: mês a mês, um ano e um ano, dois anos e dois anos.
2. Clientes com contrato mês a mês tendem a cancelar mais os serviços.

df1 %>% 
  ggplot(aes(tenure, total_charges, fill= churn))+
  geom_jitter(shape = 21, size= 3, alpha=0.5)+
  scale_fill_manual(values = c("chocolate","steelblue"))+
  facet_wrap(~ contract)+
  labs(title = "Tenure vs Total Charges by Churn and Contract")+
  theme(plot.title = element_text(hjust = 0.5, size = 18))

  1. Verdadeira , pois clientes mês a mês tem um churn maior.

gender: Se cliente é homem ou mulher. 3. Clientes do sexo masculino , tendem a ter um churn maior.

p2 <- df1 %>% 
  group_by(gender, churn) %>% 
  summarise(percent = round(n()/nrow(df1)*100,3)) %>% 
  ggplot(aes(x=gender, y=percent, fill= churn))+
  geom_bar(stat = "identity", col="black", alpha = 0.5)+
  scale_fill_manual(values = c("midnightblue", "chocolate"))+
  labs(title = "Rate of Gender by Churn",
       y = paste("percent", "%"))+
  theme(plot.title = element_text(hjust = 0.5, size = 18))
  

ggplotly(p2)
  1. Falsa , pois clientes do sexo feminino tem 13,35% equanto os homens tem 13,22%.

payment_method: Cobrança total mensal cliente por todos os seus serviços na empresa.
4. Clientes que fazem o pagamento através de transferência bancaria tendem a ter um churn maior.

df1 %>% 
  ggplot(aes(tenure, total_charges, fill= churn))+
  geom_jitter(shape = 21, size= 3, alpha=0.3)+
  scale_fill_manual(values = c("red","midnightblue"))+
  facet_wrap(~ payment_method)+
  labs(title = "Tenure vs Total Charges by Churn and Payment Method")+
  theme(plot.title = element_text(hjust = 0.5, size = 18))

4. Falsa , pois clientes que pagam seus planos por Electronic_check que é uma especie de debito automático em conta tem um churn maior.

internet_service: Se cliente tem serviço de internet: - DSL.
- Fibra óptica. - Nao possui serviço de internet.

  1. Clientes que possuem internet do tipo DSL tem um churn maior .
df1 %>% 
  ggplot(aes(tenure, total_charges, fill= churn))+
  geom_jitter(shape = 21, size= 3, alpha=0.2)+
  scale_fill_manual(values = c("cyan","midnightblue"))+
  facet_wrap(~ internet_service)+
  labs(title = "Tenure vs Total Charges by Churn and Internet Service")+
  theme(plot.title = element_text(hjust = 0.5, size = 18))

  1. Falsa , pois clientes que possuem serviço de internet fiber optic tem um churn maior.

paperless_billing : Indica se o cliente escolheu faturamento sem boleto.
5. Clientes que fazem seus pagamentos com boleto tendem mais ao churn.

p3 <- df1 %>% 
  group_by(paperless_billing, churn) %>% 
  summarise(percent = round(n()/nrow(df1)*100,3)) %>% 
  ggplot(aes(x=paperless_billing, y=percent, fill= churn))+
  geom_bar(stat = "identity", col="black", alpha = 0.2)+
  scale_fill_manual(values = c("cyan", "green"))+
  labs(title = "Rate of Paperless Billing by Churn",
       y = paste("percent", "%"))+
  theme(plot.title = element_text(hjust = 0.5, size = 18))
  

ggplotly(p3)
  1. Falsa , pois clientes que escolhem fazer pagamento sem o boleto bancario representa 20% do churn da variavel paperless_billing.